import {Object3D} from 'three';
import Mix from '../../general/mix';
import UIMesh from './ui-mesh';
import UIMaterial from './ui-material';
import UITextManager from './ui-text-manager';
import UIInline from './ui-inline';
import Constant from './ui-constant';
import UpdateManager from './ui-update-manager';
import Space from './ui-space';

export default class UIText extends Mix(Object3D)(UIInline,UITextManager,UIMaterial,UIMesh){
    constructor(options={}){
        super( options );
        this.isText = true;
        this.set( options );
    }

    get uiType(){
        return Constant.TYPE_TEXT;
    }

    parseParams() {
        this.calculateInlines(this._fitFontSize || this.getFontSize());
    }
    updateLayout() {
        UpdateManager.deepDelete( this );
        if ( this.inlines ) {
            this.textContent = this.createText();
            this.add( this.textContent );
        }
        this.position.z = this.getOffset();
    }
    updateInner() {
        this.position.z = this.getOffset();
        if ( this.textContent ) this.updateTextMaterial();
    }
    calculateInlines(fontSize){
        if ( !this.content ) {
            this.inlines = null;
            return;
        }  
        const content = this.content ;
        const breakChars = this.getBreakOn();
        const whiteSpace = this.getWhiteSpace();
        const PUI=this.getUIParent();
        const WIDTH=PUI?PUI.getWidth():Infinity;
        const SCALE=this.getScaleRatio();
        const SBH=fontSize*SCALE;
        const LN_SPS=this.getLineSpace()*SCALE;
        
        let whitespaceProcessedContent = Space.collapseContent(content,whiteSpace);
        const chars = Array.from ? Array.from( whitespaceProcessedContent ) : String( whitespaceProcessedContent ).split( '' );

        const LT_SPS=this.getLetterSpacing()*SCALE;
        const KERNING=this.getFontKerning()*SCALE;
        const lines=this.inlines||[];
        lines.length=0;

        /**generate all textures of chars,and get real-size */
        const charObjs=[];
        for(let i=0;i<chars.length;i++){
            const char=chars[i];
            charObjs[i]={
                char:char,
                height:SBH,
            };
            switch(char){
                case Constant.DEFAULT[Constant.STYLE_BREAK_LINE]:
                    break;
                case Constant.DEFAULT[Constant.STYLE_PLACEHOLDER]:
                    charObjs[i].width=SBH*0.5;
                    break;
                case ' ':
                    charObjs[i].width=SBH*0.5;
                    break;
                default:
                    this.generateCharTexture(charObjs[i]);
            }
        }

        let lineIndex=0;
        let lineLength=0;
        const growLines=(cObj,isLetter)=>{
            const w=cObj.width;
            const h=cObj.height;
            const PRF=isLetter?LT_SPS:KERNING;
            if(lineLength>WIDTH){
                lineIndex++;
                lineLength=w+PRF*2;
                cObj.x=w*0.5+PRF;
                cObj.y=-lineIndex*(h+LN_SPS)-h*0.5;
                lines[lineIndex]=[cObj];
            } else{
                cObj.x=lineLength-w*0.5;
                lineLength+=PRF;
                cObj.y=-lineIndex*(h+LN_SPS)-h*0.5;
                lines[lineIndex].push(cObj);
            }
        };
        for(let i=0;i<charObjs.length;i++){
            const charObj=charObjs[i];
            const glyph=charObj.char;
            let lineBreak = null ;
            if ( breakChars.includes( glyph ) || glyph.match(/\s/g) ) lineBreak = Constant.VALUE_POSSIBLE;
            if ( glyph.match(/\n/g) ){
                lineBreak = Space.newlineBreakability(whiteSpace);
            }
            lines[lineIndex]=lines[lineIndex]?lines[lineIndex]:[];
            let bl;
            switch(lineBreak){
                case Constant.VALUE_MANDATORY:
                    lineLength=0;
                    lineIndex++;
                    break;
                case Constant.VALUE_POSSIBLE:
                    bl=charObj.width;
                    lineLength+=bl;
                    lineLength+=KERNING;
                    growLines(charObj,false);
                    break;
                default:
                    bl=charObj.width;
                    lineLength+=bl;
                    lineLength+=LT_SPS;
                    growLines(charObj,true);
            }
        }
        this.inlines=lines;
    }

}